//
//  XMPPClient.m
//  Gildata
//
//  Created by 陆惠国 on 11-8-8.
//  Copyright 2011年 恒生聚源. All rights reserved.
//

#import "XMPPClient.h"

#import "GCDAsyncSocket.h"
#import "XMPP.h"
#import "XMPPCapabilitiesCoreDataStorage.h"
#import "XMPPRosterCoreDataStorage.h"
#import "XMPPvCardAvatarModule.h"
#import "XMPPvCardCoreDataStorage.h"

@interface XMPPClient(Private)

- (void)setupStream;
- (void)teardownStream;



@end

static XMPPClient *sharedXMPPClient = nil;

#pragma mark -

@implementation XMPPClient

@synthesize xmppStream=_xmppStream;
@synthesize xmppReconnect=_xmppReconnect;
@synthesize xmppRoster=_xmppRoster;
@synthesize xmppRosterStorage=_xmppRosterStorage;
@synthesize xmppvCardTempModule=_xmppvCardTempModule;
@synthesize xmppvCardAvatarModule=_xmppvCardAvatarModule;
@synthesize xmppCapabilities=_xmppCapabilities;
@synthesize xmppCapabilitiesStorage=_xmppCapabilitiesStorage;

@synthesize messageModule=_messageModule;
@synthesize messageStorage=_messageStorage;

@synthesize defaultAvatar = _defaultAvatar;
@synthesize lastLoginDate = _lastLoginDate;

+ (XMPPClient *)sharedInstance
{
    if (sharedXMPPClient == nil) {
        sharedXMPPClient = [[super alloc] init];
    }
    return sharedXMPPClient;
}

#pragma mark - Init/dealloc
- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
        [self setupStream];
        self.defaultAvatar = [UIImage imageNamed:@"user"];
    }
    
    return self;
}

- (void)dealloc
{
    
    [self teardownStream];

    TT_RELEASE_SAFELY(_password);
    TT_RELEASE_SAFELY(_defaultAvatar);
    TT_RELEASE_SAFELY(_lastLoginDate);
	[super dealloc];
}

#pragma mark - Core Data
- (NSManagedObjectContext *)managedObjectContext_roster
{
	NSAssert([NSThread isMainThread],
	         @"NSManagedObjectContext is not thread safe. It must always be used on the same thread/queue");
	
	if (_managedObjectContext_roster == nil)
	{
		_managedObjectContext_roster = [[NSManagedObjectContext alloc] init];
		
		NSPersistentStoreCoordinator *psc = [_xmppRosterStorage persistentStoreCoordinator];
		[_managedObjectContext_roster setPersistentStoreCoordinator:psc];
		
		[[NSNotificationCenter defaultCenter] addObserver:self
		                                         selector:@selector(contextDidSave:)
		                                             name:NSManagedObjectContextDidSaveNotification
		                                           object:nil];
	}
	
	return _managedObjectContext_roster;
}

- (NSManagedObjectContext *)managedObjectContext_capabilities
{
	NSAssert([NSThread isMainThread],
	         @"NSManagedObjectContext is not thread safe. It must always be used on the same thread/queue");
	
	if (_managedObjectContext_capabilities == nil)
	{
		_managedObjectContext_capabilities = [[NSManagedObjectContext alloc] init];
		
		NSPersistentStoreCoordinator *psc = [_xmppCapabilitiesStorage persistentStoreCoordinator];
		[_managedObjectContext_capabilities setPersistentStoreCoordinator:psc];
		
		[[NSNotificationCenter defaultCenter] addObserver:self
		                                         selector:@selector(contextDidSave:)
		                                             name:NSManagedObjectContextDidSaveNotification
		                                           object:nil];
	}
	
	return _managedObjectContext_capabilities;
}

- (NSManagedObjectContext *)managedObjectContext_message
{
	NSAssert([NSThread isMainThread],
	         @"NSManagedObjectContext is not thread safe. It must always be used on the same thread/queue");
	
	if (_managedObjectContext_message == nil)
	{
		_managedObjectContext_message = [[NSManagedObjectContext alloc] init];
		
		NSPersistentStoreCoordinator *psc = [_messageStorage persistentStoreCoordinator];
		[_managedObjectContext_message setPersistentStoreCoordinator:psc];
		
		[[NSNotificationCenter defaultCenter] addObserver:self
		                                         selector:@selector(contextDidSave:)
		                                             name:NSManagedObjectContextDidSaveNotification
		                                           object:nil];
	}
	
	return _managedObjectContext_message;
}


- (void)contextDidSave:(NSNotification *)notification
{
    @try {
        NSManagedObjectContext *sender = (NSManagedObjectContext *)[notification object];
        
        if (sender != _managedObjectContext_roster &&
            [sender persistentStoreCoordinator] == [_managedObjectContext_roster persistentStoreCoordinator])
        {
            DDLogVerbose(@"%@: %@ - Merging changes into managedObjectContext_roster", THIS_FILE, THIS_METHOD);
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                [_managedObjectContext_roster mergeChangesFromContextDidSaveNotification:notification];
            });
        }
        
        if (sender != _managedObjectContext_capabilities &&
            [sender persistentStoreCoordinator] == [_managedObjectContext_capabilities persistentStoreCoordinator])
        {
            DDLogVerbose(@"%@: %@ - Merging changes into managedObjectContext_capabilities", THIS_FILE, THIS_METHOD);
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                [_managedObjectContext_capabilities mergeChangesFromContextDidSaveNotification:notification];
            });
        }
        
        if (sender != _managedObjectContext_message &&
            [sender persistentStoreCoordinator] == [_managedObjectContext_message persistentStoreCoordinator])
        {
            DDLogVerbose(@"%@: %@ - Merging changes into managedObjectContext_message", THIS_FILE, THIS_METHOD);
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                [_managedObjectContext_message mergeChangesFromContextDidSaveNotification:notification];
            });
        }

    }
    @catch (NSException *exception) {
        DDLogWarn(@"Exception %@", exception);
    }
    @finally {
        
    }
    
}


#pragma mark - Private

- (void)setupStream
{
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
	NSAssert(_xmppStream == nil, @"Method setupStream invoked multiple times");
	
	// Setup xmpp stream
	// 
	// The XMPPStream is the base class for all activity.
	// Everything else plugs into the xmppStream, such as modules/extensions and delegates.
    
	_xmppStream = [[XMPPStream alloc] init];
	
#if !TARGET_IPHONE_SIMULATOR
	{
		// Want xmpp to run in the background?
		// 
		// P.S. - The simulator doesn't support backgrounding yet.
		//        When you try to set the associated property on the simulator, it simply fails.
		//        And when you background an app on the simulator,
		//        it just queues network traffic til the app is foregrounded again.
		//        We are patiently waiting for a fix from Apple.
		//        If you do enableBackgroundingOnSocket on the simulator,
		//        you will simply see an error message from the xmpp stack when it fails to set the property.
		
		_xmppStream.enableBackgroundingOnSocket = YES;
	}
#endif
	
	// Setup reconnect
	// 
	// The XMPPReconnect module monitors for "accidental disconnections" and
	// automatically reconnects the stream for you.
	// There's a bunch more information in the XMPPReconnect header file.
	
	_xmppReconnect = [[XMPPReconnect alloc] init];
	
	// Setup roster
	// 
	// The XMPPRoster handles the xmpp protocol stuff related to the roster.
	// The storage for the roster is abstracted.
	// So you can use any storage mechanism you want.
	// You can store it all in memory, or use core data and store it on disk, or use core data with an in-memory store,
	// or setup your own using raw SQLite, or create your own storage mechanism.
	// You can do it however you like! It's your application.
	// But you do need to provide the roster with some storage facility.
	
	_xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
    //_xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] initWithInMemoryStore];
	
	_xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppRosterStorage];
	
	_xmppRoster.autoFetchRoster = YES;
	_xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
	
	// Setup vCard support
	// 
	// The vCard Avatar module works in conjuction with the standard vCard Temp module to download user avatars.
	// The XMPPRoster will automatically integrate with XMPPvCardAvatarModule to cache roster photos in the roster.
	
	_xmppvCardStorage = [[XMPPvCardCoreDataStorage sharedInstance] retain];
	_xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:_xmppvCardStorage];
	
	_xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardTempModule];
	
	// Setup capabilities
	// 
	// The XMPPCapabilities module handles all the complex hashing of the caps protocol (XEP-0115).
	// Basically, when other clients broadcast their presence on the network
	// they include information about what capabilities their client supports (audio, video, file transfer, etc).
	// But as you can imagine, this list starts to get pretty big.
	// This is where the hashing stuff comes into play.
	// Most people running the same version of the same client are going to have the same list of capabilities.
	// So the protocol defines a standardized way to hash the list of capabilities.
	// Clients then broadcast the tiny hash instead of the big list.
	// The XMPPCapabilities protocol automatically handles figuring out what these hashes mean,
	// and also persistently storing the hashes so lookups aren't needed in the future.
	// 
	// Similarly to the roster, the storage of the module is abstracted.
	// You are strongly encouraged to persist caps information across sessions.
	// 
	// The XMPPCapabilitiesCoreDataStorage is an ideal solution.
	// It can also be shared amongst multiple streams to further reduce hash lookups.
	
	_xmppCapabilitiesStorage = [[XMPPCapabilitiesCoreDataStorage sharedInstance] retain];
    _xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:_xmppCapabilitiesStorage];
    
    _xmppCapabilities.autoFetchHashedCapabilities = YES;
    _xmppCapabilities.autoFetchNonHashedCapabilities = NO;
    
    _messageStorage = [[MessageCoreDataStorage sharedInstance] retain];
    _messageModule = [[MessageModule alloc] initWithMessageStorage:_messageStorage];
    
	// Activate xmpp modules
    
	[_xmppReconnect         activate:_xmppStream];
	[_xmppRoster            activate:_xmppStream];
	[_xmppvCardTempModule   activate:_xmppStream];
	[_xmppvCardAvatarModule activate:_xmppStream];
	[_xmppCapabilities      activate:_xmppStream];
    
    [_messageModule      activate:_xmppStream];
    
	// Add ourself as a delegate to anything we may be interested in
    
	[_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
	[_xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
    [_xmppvCardTempModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
    
    
	// Optional:
	// 
	// Replace me with the proper domain and port.
	// The example below is setup for a typical google talk account.
	// 
	// If you don't supply a hostName, then it will be automatically resolved using the JID (below).
	// For example, if you supply a JID like 'user@quack.com/rsrc'
	// then the xmpp framework will follow the xmpp specification, and do a SRV lookup for quack.com.
	// 
	// If you don't specify a hostPort, then the default (5222) will be used.
	
    //	[xmppStream setHostName:@"talk.google.com"];
    //	[xmppStream setHostPort:5222];	
	
    
	// You may need to alter these settings depending on the server you're connecting to
	_allowSelfSignedCertificates = NO;
	_allowSSLHostNameMismatch = NO;
    
}

- (void)teardownStream
{
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
	[_xmppStream removeDelegate:self];
	[_xmppRoster removeDelegate:self];
	
	[_xmppReconnect         deactivate];
	[_xmppRoster            deactivate];
	[_xmppvCardTempModule   deactivate];
	[_xmppvCardAvatarModule deactivate];
	[_xmppCapabilities      deactivate];
    
    [_messageModule        deactivate];
	
	[_xmppStream disconnect];
	
	[_xmppStream release];
	[_xmppReconnect release];
	[_xmppRoster release];
	[_xmppRosterStorage release];
	[_xmppvCardStorage release];
	[_xmppvCardTempModule release];
	[_xmppvCardAvatarModule release];
	[_xmppCapabilities release];
	[_xmppCapabilitiesStorage release];
	
	_xmppStream = nil;
	_xmppReconnect = nil;
    _xmppRoster = nil;
	_xmppRosterStorage = nil;
	_xmppvCardStorage = nil;
    _xmppvCardTempModule = nil;
	_xmppvCardAvatarModule = nil;
	_xmppCapabilities = nil;
	_xmppCapabilitiesStorage = nil;
    
    TT_RELEASE_SAFELY(_messageModule);
    TT_RELEASE_SAFELY(_messageStorage)
}


- (void)goOnline
{
	XMPPPresence *presence = [XMPPPresence presence]; // type="available" is implicit

    NSXMLElement *status = [NSXMLElement 
                            elementWithName:@"status"]; 

    if(TTIsPad()){
        [status setStringValue:@"iPad在线"]; 
        
    }else{
        [status setStringValue:@"iPhone在线"]; 
        
    }
    
    [presence addChild:status]; 
	[[self xmppStream] sendElement:presence];
}

- (void)goOffline
{
	XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
	
	[[self xmppStream] sendElement:presence];
}

- (void)goAway
{
	XMPPPresence *presence = [XMPPPresence presence]; // type="available" is implicit
    NSXMLElement *show = [NSXMLElement 
                            elementWithName:@"show"]; 
    [show setStringValue:@"away"]; 
    [presence addChild:show]; 
    NSXMLElement *status = [NSXMLElement 
                            elementWithName:@"status"]; 
    [status setStringValue:@"离开"]; 
    [presence addChild:status]; 
	[[self xmppStream] sendElement:presence];    
}



#pragma mark - Connect/disconnect
- (BOOL)connectWithJID:(NSString*) jid AndPassword:(NSString*) password{
    if (![_xmppStream isDisconnected]) {
        [_xmppStream disconnect];
    }

    
    NSString *myJID = [jid copy];
    NSString *myPassword = [password copy];
    
    

    
    if (myJID == nil || myPassword == nil) {
        DDLogWarn(@"JID and password must be set before connecting!");
        
        return NO;
    }

    
    [_xmppStream setMyJID:[XMPPJID jidWithString:myJID]];
    
    NSString* host = [[NSUserDefaults standardUserDefaults] stringForKey:kHost];
    NSInteger port = [[NSUserDefaults standardUserDefaults] integerForKey:kPort];
    if (TTIsStringWithAnyText(host)) {
        _xmppStream.hostName = host;
    }else{
        _xmppStream.hostName = nil;
    }
    
    if (port>0) {
        _xmppStream.hostPort = port;
    }else{
        _xmppStream.hostPort = 5222;
    }
    
    
    _password = myPassword;
    
    NSError *error = nil;
    if (![_xmppStream connect:&error])
    {
        TTAlert(@"连接失败");
    
        
        DDLogError(@"Error connecting: %@", error);
        
        return NO;
    }
    
    return YES;
    
}


- (BOOL)connect
{

    return  [self connectWithJID:[[NSUserDefaults standardUserDefaults] stringForKey:kJID] 
                          AndPassword:[[NSUserDefaults standardUserDefaults] stringForKey:kPassword]];
}

- (void)disconnect {
    if(![[NSUserDefaults standardUserDefaults] boolForKey: kSaveChatHistory]){
        [_messageStorage clearAllMessagesForXMPPStream:_xmppStream];
    }
    [self goOffline];    
    [_xmppStream disconnect];
}

- (void)clearAllMessages
{
    [_messageStorage clearAllMessagesForXMPPStream:_xmppStream];
}

- (void)clearAllReadedMessages
{
    [_messageStorage clearAllReadedMessagesForXMPPStream:_xmppStream];
}
- (void)clearMessagesForJID:(XMPPJID *)jid{
    [_messageStorage clearAllMessagesForXMPPStream:_xmppStream];
}

#pragma mark － XMPPStream Delegate

//- (void)xmppStreamWillConnect:(XMPPStream *)sender
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//
//- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//
//- (void)xmppStreamDidStartNegotiation:(XMPPStream *)sender
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}

- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
	DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
	
	if (_allowSelfSignedCertificates)
	{
		[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
	}
	
	if (_allowSSLHostNameMismatch)
	{
		[settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];
	}
	else
	{
		// Google does things incorrectly (does not conform to RFC).
		// Because so many people ask questions about this (assume xmpp framework is broken),
		// I've explicitly added code that shows how other xmpp clients "do the right thing"
		// when connecting to a google server (gmail, or google apps for domains).
		
		NSString *expectedCertName = nil;
		
		NSString *serverDomain = _xmppStream.hostName;
		NSString *virtualDomain = [_xmppStream.myJID domain];
		
		if ([serverDomain isEqualToString:@"talk.google.com"])
		{
			if ([virtualDomain isEqualToString:@"gmail.com"])
			{
				expectedCertName = virtualDomain;
			}
			else
			{
				expectedCertName = serverDomain;
			}
		}
		else if (serverDomain == nil)
		{
			expectedCertName = virtualDomain;
		}
		else
		{
			expectedCertName = serverDomain;
		}
		
		if (expectedCertName)
		{
			[settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
		}
	}
}


//- (void)xmppStreamDidSecure:(XMPPStream *)sender
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}

- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
	DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
	
	_isXmppConnected = YES;
	
	NSError *error = nil;
	
	if (![[self xmppStream] authenticateWithPassword:_password error:&error])
	{
		DDLogError(@"Error authenticating: %@", error);
	}
}


//- (void)xmppStreamDidRegister:(XMPPStream *)sender
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//
//- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}


- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    [self goOnline];
    self.lastLoginDate= [NSDate date];
}

//- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
	DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, [iq elementID]);
	
	return NO;
}

- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
	DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, message);
    
    
    
	if ([message isChatMessageWithBody])
	{
		XMPPUserCoreDataStorageObject *user = [_xmppRosterStorage userForJID:[message from]
                                                                  xmppStream:_xmppStream
                                                        managedObjectContext:[self managedObjectContext_roster]];
		
		NSString *body = [[message elementForName:@"body"] stringValue];
		NSString *displayName = [user displayName];
        
		if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
		{
            [[NSNotificationCenter defaultCenter] postNotificationName:kMessageReceivedNotification object:message];
		}
		else
		{
			// We are not active, so use a local notification instead
			UILocalNotification *localNotification = [[UILocalNotification alloc] init];
			localNotification.alertAction = @"Ok";
			localNotification.alertBody = [NSString stringWithFormat:@"%@\n\n%@",displayName,body];
            localNotification.soundName = UILocalNotificationDefaultSoundName;

            localNotification.applicationIconBadgeNumber = [UIApplication sharedApplication].applicationIconBadgeNumber +1 ;
			[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
			[localNotification release];
		}
	}
}

//- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
//{
//    DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, [presence fromStr]);
//}

//- (void)xmppStream:(XMPPStream *)sender didReceiveError:(NSXMLElement *)error
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//- (void)xmppStream:(XMPPStream *)sender willSendIQ:(XMPPIQ *)iq
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//- (void)xmppStream:(XMPPStream *)sender willSendMessage:(XMPPMessage *)message
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//- (void)xmppStream:(XMPPStream *)sender willSendPresence:(XMPPPresence *)presence
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//- (void)xmppStream:(XMPPStream *)sender didSendIQ:(XMPPIQ *)iq
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//- (void)xmppStream:(XMPPStream *)sender didSendPresence:(XMPPPresence *)presence
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//
//- (void)xmppStreamWasToldToDisconnect:(XMPPStream *)sender
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}


- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    if (!_isXmppConnected)
	{
		TTAlert(@"无法连接服务器，请检查服务器设置");
	}
    _isXmppConnected = NO;
}


//- (void)xmppStream:(XMPPStream *)sender didReceiveP2PFeatures:(NSXMLElement *)streamFeatures
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//
//- (void)xmppStream:(XMPPStream *)sender willSendP2PFeatures:(NSXMLElement *)streamFeatures
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//
//- (void)xmppStream:(XMPPStream *)sender didRegisterModule:(id)module
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//- (void)xmppStream:(XMPPStream *)sender willUnregisterModule:(id)module
//{
//    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
//}
//
//#pragma mark - XMPPvCardTempModuleDelegate
//- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule 
//        didReceivevCardTemp:(XMPPvCardTemp *)vCardTemp 
//                     forJID:(XMPPJID *)jid
//{
//    DDLogVerbose(@"%@: %@ - %@ %@", THIS_FILE, THIS_METHOD, vCardTemp.nickname, jid);
//}

#pragma mark - XMPPRosterDelegate

- (void)xmppRoster:(XMPPRoster *)sender didReceiveBuddyRequest:(XMPPPresence *)presence
{
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
	XMPPUserCoreDataStorageObject *user = [_xmppRosterStorage userForJID:[presence from]
	                                                         xmppStream:_xmppStream
	                                               managedObjectContext:[self managedObjectContext_roster]];    
    NSString *displayName = [user displayName];
    NSString *jidStrBare = [presence fromStr];
    NSString *body = nil;
    
    if (![displayName isEqualToString:jidStrBare]) 
    {
        body = [NSString stringWithFormat:@"Buddy request from %@ <%@>", displayName, jidStrBare];
    } 
    else 
    {
        body = [NSString stringWithFormat:@"Buddy request from %@", displayName];
    }
    
    
    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
    {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:displayName
                                                            message:body 
                                                           delegate:nil 
                                                  cancelButtonTitle:@"Not implemented" 
                                                  otherButtonTitles:nil];
        [alertView show];
        [alertView release];
    } 
    else 
    {
        // We are not active, so use a local notification instead
        UILocalNotification *localNotification = [[UILocalNotification alloc] init];
        localNotification.alertAction = @"Not implemented";
        localNotification.alertBody = body;
        
        [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
        [localNotification release];
    }
    
}

#pragma mark － Public

- (XMPPUserCoreDataStorageObject *)userForJID:(XMPPJID *) jid
{
    return [_xmppRosterStorage userForJID:jid xmppStream:_xmppStream managedObjectContext:[self managedObjectContext_roster]];
}

- (XMPPUserCoreDataStorageObject *)myUser
{
    return [_xmppRosterStorage myUserForXMPPStream:_xmppStream managedObjectContext:[self managedObjectContext_roster]];   
}

- (UIImage *)avatarForUser:(XMPPUserCoreDataStorageObject *) user
{
    UIImage* photo;
    XMPPvCardTemp* vCardTemp = [_xmppvCardTempModule fetchvCardTempForJID:user.jid];
    if (user.photo)
    {
        photo = user.photo;
    } 
    else
    {
        NSData *photoData = vCardTemp.photo;
        
        if (photoData != nil) {
            photo = [UIImage imageWithData:photoData];
        } else {
            photo = self.defaultAvatar;
        }
    }
    
    return photo;    
    
}

- (UIImage *)avatarForJID:(XMPPJID *) jid
{
    XMPPUserCoreDataStorageObject* user = [self userForJID:jid];
    return [self avatarForUser:user];    
}

- (UIImage *)myAvatar;
{
    XMPPUserCoreDataStorageObject* user = [self myUser];
    XMPPvCardTemp* vCardTemp = [_xmppvCardTempModule myvCardTemp];

    UIImage* photo;
    
    if (user.photo)
    {
        photo = user.photo;
    } 
    else
    {
        NSData *photoData = vCardTemp.photo;
        
        if (photoData != nil) {
            photo = [UIImage imageWithData:photoData];
        } else {
            photo = self.defaultAvatar;
        }
    }
    
    return photo;
    
}

- (void)saveAll
{
    NSError *error = nil;
	if (![_managedObjectContext_capabilities save:&error])
	{
		[_managedObjectContext_capabilities rollback];
	}
	if (![_managedObjectContext_roster save:&error])
	{
		[_managedObjectContext_roster rollback];
	}
    
	if (![_managedObjectContext_message save:&error])
	{
		[_managedObjectContext_message rollback];
	}    
    
}


@end
